package org.aplombh.java.awcing.basic.graph.shortestPath.spfa;

import org.aplombh.java.utils.Queue;

import java.util.Arrays;
import java.util.Scanner;

/**
 * 给定一个 n 个点 m 条边的有向图，图中可能存在重边和自环， 边权可能为负数。
 *
 * 请你判断图中是否存在负权回路。
 *
 * 输入格式
 * 第一行包含整数 n 和 m。
 *
 * 接下来 m 行每行包含三个整数 x,y,z，表示存在一条从点 x 到点 y 的有向边，边长为 z。
 *
 * 输出格式
 * 如果图中存在负权回路，则输出 Yes，否则输出 No。
 *
 * 数据范围
 * 1≤n≤2000,
 * 1≤m≤10000,
 * 图中涉及边长绝对值均不超过 10000。
 *
 * 输入样例：
 * 3 3
 * 1 2 -1
 * 2 3 4
 * 3 1 -4
 * 输出样例：
 * Yes
 */
public class Wormholes_852 {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();
        int m = scanner.nextInt();
        Spfa_2 spfa = new Spfa_2(n);
        while (m-- != 0) {
            int a = scanner.nextInt();
            int b = scanner.nextInt();
            int c = scanner.nextInt();
            spfa.add(a, b, c);
        }

        if (spfa.spfa())
            System.out.println("Yes");
        else
            System.out.println("No");
    }
}

class Spfa_2 {
    public static final int N = 10010;
    int[] h, w, e, ne; // 存储图 Store the graph

    int[] dist = new int[N]; // *** i为起点到某点的最短距离 The distance from i to some point

    int[] cnt = new int[N]; // 到该点的最短距离的路径所经过的点的个数 The number of points taken by the shortest path to the point
    boolean[] st = new boolean[N]; // 是否访问过  visited
    int n, idx;

    Spfa_2(int n) {
        init(n);
    }

    void init(int n) {
        this.n = n;
        // 初始化 initialize
        h = new int[N];
        w = new int[N];
        e = new int[N];
        ne = new int[N];
        Arrays.fill(h, -1);
//        Arrays.fill(dist, 1 << 30);
//        dist[1] = 0;
    }

    void add(int a, int b, int c) {
        w[idx] = c;
        e[idx] = b;
        ne[idx] = h[a];
        h[a] = idx++;
    }

    public boolean spfa() {
        // 新增队列存储改动的点 Add a queue to store the changed points
        Queue<Integer> q = new Queue<>();
        // 入队 enqueue
        for (int i = 1; i <= n; i++) {
            q.push(i);
            st[i] = true;
        }
        while (q.size() != 0) {
            // 出队 dequque
            int t = q.pop();
            st[t] = false;
            // 遍历邻接表 traversing adjacency List
            for (int i = h[t]; i != -1; i = ne[i]) {
                int j = e[i];
                // 如果先到t再到i比之前的距离短，更新当前距离 If the distance from t to i is shorter than the previous distance,update the current distance
                if (dist[j] > dist[t] + w[i]) {
                    dist[j] = dist[t] + w[i];
                    cnt[j] = cnt[t] + 1;
                    if (cnt[j] >= n) return true;
                    // 如果该点被更新了距离，并且未被访问过，则将该点加入队列 If the point has been updated distance and has not been accessed, the point is enqueued
                    if (!st[j]) {
                        q.push(j);
                        st[j] = true;
                    }
                }
            }
        }
        return false;
    }
}